package com.sky.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.sky.dto.SalesTop10ReportDTO;
import com.sky.entity.Orders;
import com.sky.mapper.OrderDetailMapper;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.sql.Date;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

/**
 * @program: sky-take-out
 * @description:
 * @author: 酷炫焦少
 * @create: 2024-11-20 11:10
 **/
@Service
public class ReportServiceImpl implements ReportService {

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private OrderDetailMapper orderDetailMapper;

    @Resource
    private WorkspaceService workspaceService;

    public List<LocalDate> getDateList(LocalDate begin, LocalDate end) {
        List<LocalDate> dateList = new ArrayList<>();
        while (!begin.isEqual(end)) {
            dateList.add(begin);
            begin = begin.plusDays(1);
        }
        dateList.add(begin);
        return dateList;
    }

    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {
        // 计算dateList
        List<LocalDate> dateList = getDateList(begin, end);
        // 计算每天的营业额
        // 1.先从数据库中查出来数据
        Map<Date, Map<String, Object>> amountSum = orderMapper.querySumCountByStatusAndTime(LocalDateTime.of(begin, LocalTime.MIN),
                LocalDateTime.of(end, LocalTime.MAX),
                Orders.COMPLETED);
        List<BigDecimal> amount = new ArrayList<>();
        dateList.forEach(date -> {
            Date dt = Date.valueOf(date);
            if (amountSum.containsKey(dt)) {
                Map<String, Object> dateBigDecimalMap = amountSum.get(dt);
                BigDecimal bigDecimal = (BigDecimal) dateBigDecimalMap.get("amount");
                amount.add(bigDecimal);
            } else {
                amount.add(new BigDecimal(0));
            }
        });
        return TurnoverReportVO.builder()
                .dateList(StrUtil.join(",", dateList))
                .turnoverList(StrUtil.join(",", amount))
                .build();
    }

    @Override
    public UserReportVO userStatistics(LocalDate begin, LocalDate end) {
        // 将日期存到dateList中
        List<LocalDate> dateList = getDateList(begin, end);
        // 将开始前所有的用户加起来
        Long totalUserBeforeBeginTime = userMapper.queryTotalUserBeforeBeginTime(begin);
        // 找到当天注册的所有用户（新用户）
        Map<Date, Map<String, Object>> dateMapMap = userMapper.queryNewUserBetweenTime(
                LocalDateTime.of(begin, LocalTime.MIN), LocalDateTime.of(end, LocalTime.MAX));
        List<Long> newUser = new ArrayList<>();
        List<Long> totalUser = new ArrayList<>();
        for (LocalDate date : dateList) {
            Date time = Date.valueOf(date);
            if (dateMapMap.containsKey(time)) {
                Map<String, Object> map = dateMapMap.get(time);
                Long num = (Long) map.get("num");
                newUser.add(num);
                totalUserBeforeBeginTime += num;
                totalUser.add(totalUserBeforeBeginTime);
            } else {
                newUser.add(0L);
                totalUser.add(totalUserBeforeBeginTime);
            }
        };
        // 不断加起来 就是所有用户
        return UserReportVO.builder()
                .dateList(StrUtil.join(",", dateList))
                .newUserList(StrUtil.join(",", newUser))
                .totalUserList(StrUtil.join(",", totalUser))
                .build();
    }

    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {
        List<LocalDate> dateList = getDateList(begin, end);
        Map<String, Object> params = new HashMap<>();
        params.put("begin", LocalDateTime.of(begin, LocalTime.MIN));
        params.put("end", LocalDateTime.of(end, LocalTime.MAX));
        params.put("completed", Orders.COMPLETED);
        Map<Date, Map<String, Object>> map = orderMapper.getStatistics(params);
        List<Integer> orderCountList = new ArrayList<>();
        List<Integer> validOrderCountList = new ArrayList<>();
        Integer totalOrderCount = 0;
        Integer validOrderCount = 0;
        for (LocalDate date : dateList) {
            Date time = Date.valueOf(date);
            if (map.containsKey(time)) {
                Map<String, Object> orderMap = map.get(time);
                Long total = (Long) orderMap.get("total");
                Long validOrder = (Long) orderMap.get("completed");
                int var1 = total.intValue();
                int var2 = validOrder.intValue();
                validOrderCountList.add(var2);
                orderCountList.add(var1);
                validOrderCount += var2;
                totalOrderCount += var1;
            } else {
                validOrderCountList.add(0);
                orderCountList.add(0);
            }
        }
        return OrderReportVO.builder()
                .dateList(StrUtil.join(",", dateList))
                .validOrderCountList(StrUtil.join(",", validOrderCountList))
                .orderCountList(StrUtil.join(",", orderCountList))
                .validOrderCount(validOrderCount)
                .totalOrderCount(totalOrderCount)
                .orderCompletionRate(validOrderCount * 1.0 / totalOrderCount)
                .build();
    }

    @Override
    public SalesTop10ReportVO top10(LocalDate begin, LocalDate end) {
        List<SalesTop10ReportDTO> salesTop10ReportDTOList = orderDetailMapper.queryTop10(
                LocalDateTime.of(begin, LocalTime.MIN), LocalDateTime.of(end, LocalTime.MAX));
        List<String> nameList = new ArrayList<>();
        List<Long> numberList = new ArrayList<>();
        salesTop10ReportDTOList.forEach(salesTop10ReportDTO -> {
            nameList.add(salesTop10ReportDTO.getName());
            numberList.add(salesTop10ReportDTO.getSaleCount());
        });
        return SalesTop10ReportVO.builder()
                .nameList(StrUtil.join(",", nameList))
                .numberList(StrUtil.join(",", numberList))
                .build();
    }

    @Override
    public void exportBusinessDate(HttpServletResponse response) {
        ServletOutputStream outputStream = null;
        XSSFWorkbook excel = null;
        LocalDate begin = LocalDate.now().minusDays(30);
        LocalDate end = LocalDate.now().minusDays(1);
        // 读取数据
        BusinessDataVO businessData = workspaceService.
                getBusinessData(LocalDateTime.of(begin, LocalTime.MIN), LocalDateTime.of(end, LocalTime.MAX));
        // 读取模板文件
        InputStream in = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");
        try {
            // 基于模板文件创建一个新的excel文件
            excel = new XSSFWorkbook(in);
            // 填充时间
            // Sheet注意大小写
            XSSFSheet sheet1 = excel.getSheet("Sheet1");
            // row、cell索引是从0开始的
            sheet1.getRow(1).getCell(1).setCellValue("时间：" + begin + "至" + end);
            // 获得第四行
            XSSFRow row3 = sheet1.getRow(3);
            row3.getCell(2).setCellValue(businessData.getTurnover());
            row3.getCell(4).setCellValue(businessData.getOrderCompletionRate());
            row3.getCell(6).setCellValue(businessData.getNewUsers());
            // 获得第五行
            XSSFRow row4 = sheet1.getRow(4);
            row4.getCell(2).setCellValue(businessData.getValidOrderCount());
            row4.getCell(4).setCellValue(businessData.getUnitPrice());

            // 通过输出流，将excel文件下载到客户端浏览器
            outputStream = response.getOutputStream();
            excel.write(outputStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (!Objects.isNull(outputStream)) {
                    outputStream.close();
                }
                if (Objects.isNull(excel)) {
                    excel.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
